#include "../Entetes/automate.h"

/*!
Ce constructeur permet de créer un automate trivial.
Il contient un état initial, l'alphabet est vide et.
\fn automate::automate()
\brief Constructeur par défaut.
*/
automate::automate()
{
	etats.clear();
	etats.push_back(new etat());
	for (int i=0; i<256; i++)
	{
		alphabet.push_back(false);
	}
	etat_courant = etats[0];
}

/*!
Ce constructeur permet de créer un automate par copie.
\fn automate::automate(const automate &at)
\brief Constructeur par copie.
\param const automate &at
*/
automate::automate(const automate &at)
{
	etats.clear();
	for (unsigned int i=0; i<at.etats.size(); i++)
	{
		etat *etat_tmp = new etat();
		(etat_tmp) = (at.etats[i]);
		etats.push_back(etat_tmp);
	}

	alphabet=at.alphabet;
	etat *etat_c = new etat();
	*etat_c = *(at.etat_courant);
	etat_courant= etat_c;
}
/*
automate::~automate()
{
	//libération de la mémoire utilisée par les états
	for(std::vector<etat*>::const_iterator it_etat = etats.begin(); it_etat != etats.end(); ++it_etat )
	{
		delete *it_etat;
	}

	//libération de la mémoire utilisée par les alphabets
	alphabet.clear();

	//etat_courant a été libéré en même temps que tous les autres états, on ne le libère donc plus. Il est inutile de le mettre à NULL.
}*/

/*!
Ce constructeur permet de créer un automate où l'état initial est un puits.
\fn void automate::automate_puits()
\brief Constructeur d'un automate puits.
\deprecated
*/
void automate::automate_puits()
{
	etat *initial = new etat();
	initial->etat_puits();
	etats.push_back(initial);
	for (int i=0; i<256; i++)
	{
		alphabet.push_back(false);
	}
	etats.clear();
}

/*!
Permet d'ajouter un état à un automate
\fn void automate::automate_ajoute_etat(etat *et)
\param etat *et
*/
void automate::automate_ajoute_etat(etat *et)
{
	etats.push_back(et);
}

/*!
Permet d'ajouter un état final à un automate
\fn void automate::automate_ajoute_final(etat* et, int code)
\param etat* et, int code
*/
void automate::automate_ajoute_final(etat* et, int code)
{
	etats.push_back(et);
	etats_finaux.push_back(et);
	et->set_final(code);
}

/*!
Permet d'ajouter une transition entre deux états dans un automate
\fn void automate::ajoute_transition(etat* precedent, etat* suivant, unsigned char caract)
\param etat* precedent, etat* suivant, unsigned char caract
*/
void automate::ajoute_transition(etat* precedent, etat* suivant, unsigned char caract)
{
	precedent->set_transition(suivant, caract, 1);
	alphabet[caract]= true;
}

/*!
Permet d'ajouter une epsilon-transition entre deux états dans un automate
\fn void automate::ajoute_epsilon_transition(etat* precedent, etat* suivant)
\param etat* precedent, etat* suivant
*/
void automate::ajoute_epsilon_transition(etat* precedent, etat* suivant)
{
	precedent->set_epsilon(suivant, 1);
}

/*!
met à jour l'ensemble des transitions entre les états precedent et suivant
\fn void automate::ajoute_transitions(etat* precedent, etat* suivant, transitions trans)
\param etat* precedent, etat* suivant
*/
void automate::ajoute_transitions(etat* precedent, etat* suivant, transitions trans)
{
	precedent->set_transitions(suivant, trans);
	for(int i=0; i<256; i++)
	{
		alphabet[i] = (alphabet[i] || trans.get_trans(i));
	}
}

/*!
renvoie l'automate qui reconnaît l'expression régulière A* si aut reconnait A. Laisse aut inchangé
\fn automate& automate::plus(automate *aut)
\param automate *aut
*/
automate& automate::plus(automate *aut)
{
	automate *aplus = new automate(*(aut));

	for(unsigned int i=0; i < aplus->etats_finaux.size(); i++)
	{
		aplus->etats_finaux[i]->set_epsilon(aplus->etats[0],1);
	}

	return *aplus;
}

/*!
renvoie l'automate qui reconnaît l'expression régulière A? si aut reconnait A. Laisse aut inchangé
\fn automate& automate::interrog(automate *aut)
\param automate *aut
*/
automate& automate::interrog(automate *aut)
{
	automate *aplus = new automate(*(aut));

	for(unsigned int i=0; i < aplus->etats_finaux.size(); i++)
	{
		aplus->etats[0]->set_epsilon(aplus->etats_finaux[i],1);
	}

	return *aplus;
}

/*!
renvoie l'automate qui reconnaît l'expression régulière A* si aut reconnait A. Laisse aut inchangé
\fn automate& automate::etoile(automate *aut)
\param automate *aut
*/
automate& automate::etoile(automate *aut)
{
	automate *aplus = new automate(*(aut));

	for(std::vector<etat*>::iterator it_etat = aplus->etats_finaux.begin(); it_etat != etats_finaux.end(); it_etat++ )
	{
		(*it_etat)->set_epsilon(aplus->etats[0],1);
		(*it_etat)->set_final(0);
		aplus->etats[0]->set_epsilon((*it_etat),1);
		aplus->etats_finaux.erase(it_etat);
	}

	return *aplus;
}

/*!
renvoie l'automate qui reconnaît l'expression régulière A ou l'expression régulière B si aut1 reconnait A et aut2 B. Laisse aut1 et aut2 inchangés
\fn automate& automate::addition(automate *aut1, automate *aut2)
\param automate *aut1, automate *aut2
*/
automate& automate::addition(automate *aut1, automate *aut2)
{
	automate *aut = new automate();
	for (unsigned int eta=0; eta<aut1->etats.size(); eta++)
		aut->automate_ajoute_etat(aut1->etats[eta]);
	for (unsigned int eta=0; eta<aut2->etats.size(); eta++)
		aut->automate_ajoute_etat(aut2->etats[eta]);

	aut->ajoute_epsilon_transition(aut->etats[0],aut1->etats[0]);
	aut->ajoute_epsilon_transition(aut->etats[0],aut2->etats[0]);
	for(int i=0; i<256; i++)
	{
		aut->alphabet[i] = (aut1->alphabet[i] || aut2->alphabet[i]);
	}
	return *aut;
}


/*!
renvoie l'automate qui reconnaît l'expression régulière AB si aut1 reconnait A et aut2 B. Laisse aut1 et aut2 inchangés
\fn automate& automate::concatenation(automate *aut1, automate *aut2)
\param automate *aut1, automate *aut2
*/
automate& automate::concatenation(automate *aut1, automate *aut2)
{
	automate *aut = new automate();

	for (unsigned int eta=0; eta<aut1->etats.size(); eta++)
		aut->automate_ajoute_etat(aut1->etats[eta]);
	for (unsigned int eta=0; eta<aut2->etats.size(); eta++)
		aut->automate_ajoute_etat(aut2->etats[eta]);

	aut->ajoute_epsilon_transition(aut->etats[0],aut1->etats[0]);
	for(unsigned int i=0; i < aut1->etats_finaux.size(); i++)
	{
		aut->ajoute_epsilon_transition(aut1->etats_finaux[0],aut2->etats[0]);
	}

	aut->etats_finaux = aut2->etats_finaux;
	
	for(int i=0; i<256; i++)
	{
		aut->alphabet[i] = (aut1->alphabet[i] || aut2->alphabet[i]);
	}
	etat_courant = etats[0];
	return *aut1;
}

/*!
affichage de l'automate, mais là encore, c'est pas du tout de qu'on croit
\fn void automate::affichage()
\deprecated
*/
void automate::affichage()
{
	cout << "affichage de l'automate en mode texte" <<endl;

	for(std::vector<etat*>::iterator it_etat = etats.begin(); it_etat != etats.end(); it_etat++ )
	{
		(*it_etat)->affichage();
	}
}
